所謂測試驅動開發(Test-driven development, TDD),即「先寫測試再開發」,寫一段程式,以測試功能是否正常,確保程式依照預期行為運作。有關基本原理及JavaScript中的使用,詳參延伸閱讀(這裡)。本文另以Ruby語言展示之。
撰寫測試應吻合3A原則,即Arrange(安排好)、Act(踢他兩下)、Assertion(斷言/條件)。
const moreThanChars = (chars, n) => /.{8,}/.test(chars)
test("應該要超過 8 個字 part 1", () => {
let result = moreThanChars("abc", 8)
expect(result).toBe(false)
})
test("應該要超過 8 個字 part 2", () => {
let result = moreThanChars("abc283209138021832", 8)
expect(result).toBe(true)
})
function test(title, callback) {
try {
callback() //萬一上面的callback壞了
console.log(`✓ ${title}`); //沒壞印這個
}
catch(err) {
console.error(`✗ ${title}`) //壞了印這個
console.error(err) //印出來
}
}
function expect(result) {
return {
toBe: (expected) => {
if (result !== expected) {
throw new Error(`${result} 與預期的 ${expected} 不符!`)
}
}
}
}
在Ruby中,內建有「minitest」測試框架。特點是速度快,但難寫。另一個測試框架「RSpec」比較主流,須額外安裝,執行慢但語法易懂。
撰寫完畢的測試檔,以指令「rspec 測試檔名稱.rb」執行即可。
本文以ATM取/存款功能為例,設定測試條件及效果如下:
存錢功能
領錢功能
class ATM
def initialize(balance)
@balance = balance #初始化進實體變數
end
def withdraw(money)
if money > 0 and money <= @balance
@balance = @balance - money
return money
else
return 0 #領錢小於0的話 不給領錢
end
end
def deposit(money)
@balance = @balance + money if money > 0
end
def balance
@balance #剩下就是餘額
end
end
RSpec.describe ATM do
context"領錢功能" do
it "可以領錢" do
atm = ATM.new(10)
atm.withdraw(10)
expect(atm.balance).to be 0
end
it "不能領0元" do
atm = ATM.new(10)
atm.withdraw(-50)
expect(atm.balance).to be 10
end
it "不能領超過餘額" do
atm = ATM.new(20)
money = atm.withdraw(30)
expect(atm.balance).to be 20
expect(money).to be 0
end
end
context"存錢功能" do
it "可以存錢" do
atm = ATM.new(10)
atm.deposit(20)
expect(atm.balance).to be 30 #(be(30)) 這是matcher
end
end
context"存錢功能的限制" do
it "不可存0元以下數額" do
atm = ATM.new(10)
atm.deposit(-20)
expect(atm.balance).to be 10 #判斷餘額是否10元
end
end
end